package jp.co.nes.awssupport.access.dao;

import java.sql.Connection;
import java.sql.SQLException;
import java.time.YearMonth;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.dbutils.BasicRowProcessor;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler;

import jp.co.nes.awssupport.common.base.CommonException;
import jp.co.nes.awssupport.common.bean.TaxAssignedBean;
import jp.co.nes.awssupport.common.dao.BaseJdbcDao;
import jp.co.nes.awssupport.common.dao.BeanProcessorEx;
import jp.co.nes.awssupport.common.dao.ReadType;
import jp.co.nes.awssupport.common.utility.DateUtil;
import jp.co.nes.awssupport.common.utility.DbConnUtil;

/**
 * 税金適用DAOです。
 */
public class TaxAssignedDao extends BaseJdbcDao<TaxAssignedBean> {

    /** 税金適用を検索する際に使用するSelect文 */
    private static final String READ_TOTALIZATION_YEAR_MONTH = ""
            + "select LinkedAccountId,"
            + "       YearMonth,"
            + "       null as AssignedPlanId,"
            + "       null as AssignedGroupId,"
            + "       null as AssignedTaxName,"
            + "       TRUNCATE(min(TargetAmount) + 0.5, 0) as TargetAmount,"
            + "       TRUNCATE(sum(TRUNCATE(TaxAmount + 0.0005, 3)) + 0.5, 0) as TaxAmount"
            + "  from tax_assigned "
            + " where YearMonth = ?"
            + " group by LinkedAccountId, YearMonth";

    /** 税金適用を検索する際のSelect文 */
    private static final String SEL = ""
            + "select LinkedAccountId,"
            + "       YearMonth,"
            + "       AssignedPlanId,"
            + "       AssignedGroupId,"
            + "       AssignedTaxName,"
            + "       TargetAmount,"
            + "       TaxAmount"
            + "  from tax_assigned"
            + " where LinkedAccountId = ?"
            + "   and YearMonth = ?";

    /** 税金適用を登録する際に使用するInsert文 */
    private static final String BATCH_INS = ""
            + "insert into tax_assigned ("
            + "    LinkedAccountId,"
            + "    YearMonth,"
            + "    AssignedPlanId,"
            + "    AssignedGroupId,"
            + "    AssignedTaxName,"
            + "    TargetAmount,"
            + "    TaxAmount)"
            + " values (?, ?, ?, ?, ?, ?, ?)";

    /** 税金適用を削除する際に使用するDeletet文 */
    private static final String DEL_LINKEDACCOUNTID_YEARMONTH = ""
            + "delete from tax_assigned"
            + " where LinkedAccountId = ?"
            + "   and YearMonth = ?";

    /**
     * 税金適用を読み込む際の区分です。
     */
    public enum DaoReadType implements ReadType {

        /** READ_YEAR_MONTHを使用して読み込む場合 */
        TOTALIZATION_YEAR_MONTH(READ_TOTALIZATION_YEAR_MONTH);

        /** Select文 */
        private String select;

        /**
         * Select文を引数にもつコンストラクタです。
         *
         * @param select Select文
         */
        private DaoReadType(String select) {
            this.select = select;
        }

        /*
         * (非 Javadoc)
         * @see jp.co.nes.awssupport.common.constant.ReadType#getSelect()
         */
        @Override
        public String getSelect() {
            return select;
        }
    }

    /**
     * デフォルトコンストラクタです。
     */
    public TaxAssignedDao() {
    }

    /**
     * 引数に該当する税金適用の一覧を返却します。<br>
     * 該当する税金適用が存在しない場合は空リストを返却します。
     *
     * @param linkedAccountId 連結アカウントID
     * @param yearMonth 年月
     * @return 税金適用の一覧
     */
    public List<TaxAssignedBean> getList(String linkedAccountId, YearMonth yearMonth) {
        try {
            Connection connection = DbConnUtil.getConn();

            List<Object> paramList = new ArrayList<>();
            paramList.add(linkedAccountId);
            paramList.add(DateUtil.toInt(yearMonth));
            Object[] params = paramList.toArray();

            QueryRunner runner = new QueryRunner();
            return runner.query(connection, SEL,
                    new BeanListHandler<>(TaxAssignedBean.class, new BasicRowProcessor(new BeanProcessorEx())),
                    params);
        } catch (SQLException e) {
            throw new CommonException(e);
        }
    }

    /**
     * 引数に該当する税金適用を削除します。
     *
     * @param linkedAccountId 連結アカウントID
     * @param yearMonth 年月
     */
    public void delete(String linkedAccountId, YearMonth yearMonth) {
        try {
            Connection connection = DbConnUtil.getConn();

            Object[] params = new Object[2];
            params[0] = linkedAccountId;
            params[1] = DateUtil.toInt(yearMonth);

            QueryRunner runner = new QueryRunner();
            runner.update(connection, DEL_LINKEDACCOUNTID_YEARMONTH, params);
        } catch (SQLException e) {
            throw new CommonException(e);
        }
    }

    /*
     * (非 Javadoc)
     * @see jp.co.nes.awssupport.common.dao.BaseJdbcDao#getBatchInsQuery()
     */
    @Override
    protected String getBatchInsQuery() {
        return BATCH_INS;
    }

    /*
     * (非 Javadoc)
     * @see jp.co.nes.awssupport.common.dao.BaseJdbcDao#toConditionList(jp.co.nes.awssupport.common.constant.ReadType, java.lang.Object[])
     */
    @Override
    protected List<Object> toConditionList(ReadType readType, Object... conditions) {
        List<Object> conditionList = new ArrayList<>();
        if (readType == DaoReadType.TOTALIZATION_YEAR_MONTH) {
            conditionList.add(conditions[0]);
        } else {
            throw new CommonException("ReadType is wrong");
        }
        return conditionList;
    }

    /*
     * (非 Javadoc)
     * @see jp.co.nes.awssupport.common.dao.BaseJdbcDao#toBatchInsObjectList(jp.co.nes.awssupport.common.bean.BaseBean)
     */
    @Override
    protected List<Object> toBatchInsObjectList(TaxAssignedBean bean) {
        List<Object> objectList = new ArrayList<>();
        objectList.add(bean.getLinkedAccountId());
        objectList.add(bean.getYearMonth());
        objectList.add(bean.getAssignedPlanId());
        objectList.add(bean.getAssignedGroupId());
        objectList.add(bean.getAssignedTaxName());
        objectList.add(bean.getTargetAmount());
        objectList.add(bean.getTaxAmount());
        return objectList;
    }
}
